(function() {
	'use strict';
	/**
	 * (en)scatterDirective 
	 * @ko scatterDirective
	 * @group Directive
	 * @name scatterDirective
	 * @class
	 */
	pinpointApp.constant('scatterDirectiveConfig', {
	    get: {
	        scatterData: '/getScatterData.pinpoint',
	        lastScatterData: '/getLastScatterData.pinpoint'
	    },
	    useIntervalForFetching: false,
	    nFetchingInterval: 2000,
	    nFetchLimit: 5000,
	    options: {
	        sContainerId: '',
	        nWidth: 400,
	        nHeight: 250,
	        nXMin: 0, nXMax: 1000,
	        nYMin: 0, nYMax: 10000,
	        nZMin: 0, nZMax: 5,
	        nBubbleSize: 3,
	        sXLabel: '',
	        sYLabel: '(ms)',
	        sTitle: '',
	        'htGuideLine': {
	            'nLineWidth': 1,
	            'aLineDash': [1, 0],
	            'nGlobalAlpha': 1,
	            'sLineColor' : '#e3e3e3'
	        },
	        htTypeAndColor: {
	            // type name : color
	            'Success': '#2ca02c',
	            // 'Warning' : '#f5d025',
	            'Failed': '#d62728'
	        },
	        htOption: {
	            headers: {
	                accept: 'application/json'
	            },
	            dataType: 'json'
	        },
	        index: {
	            x: 0,
	            y: 1,
	            transactionId: 2,
	            type: 3
	        },
	        type: {
	            '0': 'Failed',
	            '1': 'Success'
	        },
	        'htCheckBoxImage': {
	            'checked' : '',
	            'unchecked' : ''
	        },
	        'sConfigImage': '',
	        'sDownloadImage': '',
	        'sFullScreenImage': ''
	    }
	});
	
	// FIXME made global to allow access from the child window. Refactor later. 
	//var selectdTracesBox = {};
	
	pinpointApp.directive('scatterDirective', ['scatterDirectiveConfig', '$rootScope', '$timeout', 'webStorage', 'TransactionDaoService', '$window', 'helpContentTemplate', 'helpContentService', 'AnalyticsService',
        function (cfg, $rootScope, $timeout, webStorage, oTransactionDaoService, $window, helpContentTemplate, helpContentService, analyticsService) {
            return {
                template: '<div id="scatter"></div>',
                restrict: 'EA',
                replace: true,
                link: function (scope, element, attrs) {

                    // define private variables
                    var oNavbarVoService, htScatterSet, htLastNode;

                    // define private variables of methods
                    var getDataSource, makeScatter, showScatter, showScatterBy, pauseScatterAll, makeScatterWithData;

                    // initialize
                    oNavbarVoService = null;
                    htScatterSet = {};
                    htLastNode = {};

                    /**
                     * get data source
                     * @param applicationName
                     * @param from
                     * @param to
                     * @param period
                     * @param filter
                     */
                    getDataSource = function (applicationName, from, to, filter) {
                        var bDrawOnceAll = false;
                        var htDataSource = {
                            sUrl: function (nFetchIndex) {
                                return cfg.get.scatterData;
                            },
                            htParam: function (nFetchIndex, htLastFetchedData) {
                                // calculate parameter
                                var htData;
                                if (nFetchIndex === 0) {
                                    htData = {
                                        'application': applicationName,
                                        'from': from,
                                        'to': to,
                                        'limit': cfg.nFetchLimit,
                                        'v': 2
                                    };
                                } else {
                                    htData = {
                                        'application': applicationName,
                                        // array[0] : most recent
                                        // array[len] : oldest
                                        'from': from,
                                        'to': htLastFetchedData.resultFrom - 1,
                                        'limit': cfg.nFetchLimit,
                                        'v': 2
                                    };
                                }
                                if (filter) {
                                    htData.filter = filter;
                                }

                                return htData;
                            },
                            nFetch: function (htLastFetchedData) {
                                // -1 : stop, n = 0 : immediately, n > 0 : interval
                                if (htLastFetchedData.resultFrom - 1 > from) {
                                    if (cfg.useIntervalForFetching) {
                                        bDrawOnceAll = true;
                                        return cfg.nFetchingInterval;
                                    }
                                    // TO THE NEXT
                                    return 0;
                                }

                                // STOP
                                return -1;
                            },
                            htOption: {
                                headers: {
                                    accept: 'application/json'
                                },
                                dataType: 'json'
                            },
                            index: {
                                x: 0,
                                y: 1,
                                transactionId: 2,
                                type: 3
                            },
                            type: {
                                '0': 'Failed',
                                '1': 'Success'
                            }
                        };
                        return htDataSource;
                    };

                    /**
                     * make scatter
                     * @param title
                     * @param start
                     * @param end
                     * @param period
                     * @param filter
                     * @param w
                     * @param h
                     * @param scatterData
                     */
                    makeScatter = function (target, title, start, end, period, filter, w, h, scatterData) {
//                        if (!Modernizr.canvas) {
//                            alert("Can't draw scatter. Not supported browser.");
//                        }

                        var options = angular.copy(cfg.options);
                        options.sPrefix = "bigscatterchart-" + parseInt( Math.random() * 100000 ) + "-";
                        options.sContainerId = target;
                        options.nWidth = w ? w : 400;
                        options.nHeight = h ? h : 250;
                        options.nXMin = start;
                        options.nXMax = end;
//                        options.sTitle = title;
                        options.fOnSelect = function (htPosition, htXY) {
//                            var transactions = {
//                                htXY: htXY,
//                                aTraces: []
//                            };
                            
                            // by netspider
//                            console.log(target, title, start, end, period, filter, w, h);
//                            var NEW_URL = "/transactionmetadata2.pinpoint?application=" + title;
//                            NEW_URL += "&from=" + htXY.nXFrom;
//                            NEW_URL += "&to=" + htXY.nXTo;
//							NEW_URL += "&responseFrom="+ htXY.nYFrom;
//							NEW_URL += "&responseTo=" + htXY.nYTo;
//							NEW_URL += "&limit=3";
//							if (filter) {
//								NEW_URL += "&filter=" + filter;
//							}
                            // var ww = window.open(NEW_URL);
                            // end

//                            transactions.aTraces = this.getDataByXY(htXY.nXFrom, htXY.nXTo, htXY.nYFrom, htXY.nYTo);
//                            if (transactions.aTraces.length === 0) {
//                                return;
//                            }
                            if (!this.hasDataByXY(htXY.nXFrom, htXY.nXTo, htXY.nYFrom, htXY.nYTo)) {
                                return;
                            }

//                            var token = 'transactionsFromScatter_' + _.random(100000, 999999);
//                            webStorage.session.add(token, transactions);
//                            window[token] = transactions;
//                            window.open("/selectedScatter.pinpoint", token);
//                            oTransactionDaoService.addData(token, transactions);

                            var token = title + '|' + htXY.nXFrom + '|' + htXY.nXTo + '|' + htXY.nYFrom + '|' + htXY.nYTo;
                            $window.open('#/transactionList/' + oNavbarVoService.getApplication() + '/' +
                                oNavbarVoService.getReadablePeriod() + '/' + oNavbarVoService.getQueryEndDateTime(), token);
                        };
                        options.fFullScreenMode = function () {
                            var url = '#/scatterFullScreenMode/' + htLastNode.applicationName + '@' + htLastNode.serviceTypeCode + '/' +
                                oNavbarVoService.getReadablePeriod() + '/' + oNavbarVoService.getQueryEndDateTime();
                            if (oNavbarVoService.getFilter()) {
                                url += '/' + oNavbarVoService.getFilter();
                            }
                            $window.open(url, "width=900, height=700, resizable=yes");
                        };

                        var oScatterChart = null;
                        oScatterChart = new BigScatterChart(options, helpContentTemplate, helpContentService, webStorage, analyticsService);
                        $timeout(function () {
                            if (angular.isUndefined(scatterData)) {
                                oScatterChart.drawWithDataSource(getDataSource(title, start, end, filter));
                            } else {
                                oScatterChart.addBubbleAndMoveAndDraw(scatterData.scatter, scatterData.resultFrom);
                            }
                            $window.htoScatter[title] = oScatterChart;
                        }, 100);

                        return oScatterChart;
                    };

                    /**
                     * show scatter
                     * @param title
                     * @param start
                     * @param end
                     * @param period
                     * @param filter
                     * @param w
                     * @param h
                     * @todo data is simply cached - might be a good idea to add pause/resume when loading scatter data to reduce server load.
                     *       adding pause/resume methods to BigScatterChart.js, and invoking them below would work.
                     */
                    showScatter = function (title, start, end, period, filter, w, h) {
                        element.children().hide();
                        pauseScatterAll();
                        if (angular.isDefined(htScatterSet[title])) {
                            htScatterSet[title].target.show();
                            htScatterSet[title].scatter.resume();
                        } else {
                            var target = angular.element('<div class="scatter">');
                            var oScatter = makeScatter(target, title, start, end, period, filter, w, h);
                            htScatterSet[title] = {
                                target : target,
                                scatter : oScatter
                            };
                            element.append(target);
                        }
                    };

                    /**
                     * show scatter by
                     * @param title
                     */
                    showScatterBy = function (title) {
                        element.children().hide();
                        if (angular.isDefined(htScatterSet[title])) {
                            htScatterSet[title].target.show();
                        }
                    };

                    /**
                     * make scatter with data
                     * @param title
                     * @param start
                     * @param end
                     * @param period
                     * @param filter
                     * @param w
                     * @param h
                     * @param data
                     */
                    makeScatterWithData = function (title, start, end, period, filter, w, h, data) {
                        if (angular.isDefined(htScatterSet[title])) {
                            htScatterSet[title].scatter.addBubbleAndMoveAndDraw(data.scatter, data.resultFrom);
                        } else {
                            var target = angular.element('<div class="scatter">');
                            var oScatter = makeScatter(target, title, start, end, period, filter, w, h, data);
                            htScatterSet[title] = {
                                target : target,
                                scatter : oScatter
                            };
                            element.append(target);
                            target.hide();
                        }
                    };

                    /**
                     * pause scatter all
                     */
                    pauseScatterAll = function () {
                        angular.forEach(htScatterSet, function (scatterSet, key) {
                            scatterSet.scatter.pause();
                        });
                    };

                    /**
                     * scope event on scatter.initialize
                     */
                    scope.$on('scatterDirective.initialize', function (event, navbarVoService) {
                        oNavbarVoService = navbarVoService;
                        htScatterSet = {};
                        element.empty();
                    });

                    /**
                     * scope event on scatter.initializeWithNode
                     */
                    scope.$on('scatterDirective.initializeWithNode', function (event, node, w, h) {
                        htLastNode = node;
                        showScatter(node.applicationName, oNavbarVoService.getQueryStartTime(),
                            oNavbarVoService.getQueryEndTime(), oNavbarVoService.getQueryPeriod(), oNavbarVoService.getFilter(), w, h);
                    });

                    /**
                     * scope event on scatter.initializeWithData
                     */
                    scope.$on('scatterDirective.initializeWithData', function (event, applicationName, data) {
                        htLastNode = {
                            applicationName: applicationName.split('^')[0]
                        };
                        makeScatterWithData(applicationName, oNavbarVoService.getQueryStartTime(),
                            oNavbarVoService.getQueryEndTime(), oNavbarVoService.getQueryPeriod(), oNavbarVoService.getFilter(), null, null, data);
                    });

                    /**
                     * scope event on scatter.showByNode
                     */
                    scope.$on('scatterDirective.showByNode', function (event, node) {
                        htLastNode = node;
                        showScatterBy(node.key);
                    });
                    scope.$on('responseTimeChartDirective.errorClicked', function(event) {
                    	// max size of drag box
                    	var oParam = {
                			animate: function() {},
                			css : function( param ) {
                				if ( param === "left" ) return "51px";
                				else return "40px";
                			},
                			width: function() {
                				return 320;
                			},
                			height: function() {
                				return 200;
                			}
                		};
                    	$window.htoScatter[htLastNode.applicationName].selectFailedOnly().fireDragEvent( oParam );
                    });
                }
            };
        } 
    ]);
})();